package sanrenxing.dayEnd.backRepertoryTotal.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sanrenxing.dayEnd.backRepertoryTotal.dao.MoneyitiesDao;
import sanrenxing.dayEnd.backRepertoryTotal.dao.RepertoryTotalDao;
import sanrenxing.dayEnd.backRepertoryTotal.dao.SecuritiesDao;
import sanrenxing.dayEnd.backRepertoryTotal.dao.TransferInstructionDao;
import sanrenxing.dayEnd.backRepertoryTotal.domain.*;
import sanrenxing.dayEnd.backRepertoryTotal.service.RepertoryTotalService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @authors name:邓志强
 * @descriptions:库存管理业务层类
 * @date: 2021/5/15 15:03
 * @version:1.0
 */
@Service("repertoryTotalService")
public class RepertoryTotalServiceImpl implements RepertoryTotalService {

    //引用库存dao的对象
    @Resource(name = "repertoryTotalDao")
    private RepertoryTotalDao repertoryTotalDao;

    //注入现金应收应付dao对象
    @Autowired
    private MoneyitiesDao moneyitiesDao;

    //注入证券应收应付dao对象
    @Autowired
    private SecuritiesDao securitiesDao;

    //注入划款指令dao对象
    @Autowired
    private TransferInstructionDao transferInstructionDao;

    /**
     * 处理五大库存的方法
     */
    @Transactional
    @Override
    public Boolean updateRepertory() {
        try {
            //通过库存统计dao对象调用证券存入证券库存统计方法
            repertoryTotalDao.reToStockTotal();
            //通过聚合函数将证券库存统计相同证券编号的数据统计成一条,调用统计方法，并且计算其单位价格，统计股票
            List<SecuritiesStock> securitiesStocks = repertoryTotalDao.TotalReStock();
            //通过聚合函数将证券库存统计相同证券编号的数据统计成一条，并且计算其单位价格，统计债券
            List<SecuritiesStock> securitiesStocksBond = repertoryTotalDao.TotalReStockBond();
            //删除证券库存中所有数据
            repertoryTotalDao.deleteReStock();
            //遍历股票集合将统计好的数据重新添加到证券库存,添加股票
            for (SecuritiesStock securitiesStock : securitiesStocks) {
                //调用证券库存的添加方法
                repertoryTotalDao.addReStock(securitiesStock);
            }
            //遍历债券集合将统计好的数据重新添加到证券库存,添加债券
            for (SecuritiesStock stock : securitiesStocksBond) {
                //调用证券库存添加方法
                repertoryTotalDao.addReStock(stock);
            }

            //创建日期格式转换对象
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

            //调用方法，让现金应收应付库存的数据添加到ta库存当中
            repertoryTotalDao.addCashToTaStock();

            //统计现金库存:将资金调拨的数据添加到现金库存当中，首先取出未处理，且调拨日期为当日的数据保存到对象当中
            //调用方法查询资金调拨数据添加到现金库存，传入当天数据
            List<FundAllocation> fundData = repertoryTotalDao.queryMoneyTransferToCashStock(dateFormat.format(new Date()));
            //遍历查询数据：处理现金应收应付的对冲销:这里只是准备数据
            for (FundAllocation fundDatum : fundData) {
                //创建现金应收应付对象
                CashReceivable cashReceivable = new CashReceivable();
                //修改对象中的业务日期为今天
                cashReceivable.setBusinDate(new Date());
                //修改现金编号为基金遍历得出的编号
                cashReceivable.setCaId(fundDatum.getCaId());
                //修改金额为基金遍历得出的调拨金额
                cashReceivable.setMoney(fundDatum.getReMoney());
                //修改基金编号为基金遍历得出的基金编号
                cashReceivable.setFundId(fundDatum.getFundId());
                //将状态修改为0：未处理
                cashReceivable.setStates(0);
                //创建证券应收应付对象：对象名为应收和应付
                ReceivableAndPayable payable = new ReceivableAndPayable();
                //修改业务日期为当天
                payable.setBusinDate(new Date());
                //修改现金编号为基金遍历的出的现金编号，需要装换为字符串
                payable.setCaId(String.valueOf(fundDatum.getCaId()));
                //修改金额为基金遍历得出的调拨金额
                payable.setMoney(fundDatum.getReMoney());
                //修改基金编号为基金遍历得出的基金编号
                payable.setFundId(fundDatum.getFundId());
                //修改状态为0:未处理
                payable.setStates(0);
                //修改证券编名为：无
                payable.setSeId("无");
                //判断基金遍历得出的类型是否为：存款业务 并且调拨反向为-1：流出
                if (fundDatum.getReType().equals("存款业务") && fundDatum.getDial()==-1){//存款业务的现金应收应付反冲销：这里只需要处理存款时，不包括退款时
                    //修改现金应收应付的交易类型为：存款
                    cashReceivable.setBusinType("存款");
                    //修改现金应收应付的资金方向为流入
                    cashReceivable.setCapFlow(1);
                    //通过现金应收应付dao对象调用添加方法将现金应收应付对象添加进去
                    moneyitiesDao.add(cashReceivable);
                    //判断类型是否为：赎回款
                }else if (fundDatum.getReType().equals("赎回款")){//在现金应收应付产生赎回款的反冲销数据
                    //修改现金应收应付对象的交易类型为：赎回款
                    cashReceivable.setBusinType("赎回款");
                    //修改现金应收应付的资金方向为流入
                    cashReceivable.setCapFlow(1);
                    //通过现金应收应付调用添加方法将现金应收应付对象添加进去
                    moneyitiesDao.add(cashReceivable);
                    //判断类型是否为：申购款
                }else if (fundDatum.getReType().equals("申购款")){//现金应收应付产生申购款的反冲销数据
                    //修改现金应收应付对象的交易类型为：申购款
                    cashReceivable.setBusinType("申购款");
                    //修改现金应收应付的资金方向为流出
                    cashReceivable.setCapFlow(-1);
                    //通过现金应收应付调用添加方法将现金应收应付对象添加进去
                    moneyitiesDao.add(cashReceivable);
                    //判断类型是否为：认购款
                }else if (fundDatum.getReType().equals("认购款")){//现金应收应付产生认购款的反冲销数据
                    //修改现金应收应付对象的交易类型为：认购款
                    cashReceivable.setBusinType("认购款");
                    //修改现金应收应付的资金方向为流出
                    cashReceivable.setCapFlow(-1);
                    //通过现金应收应付调用添加方法将现金应收应付对象添加进去
                    moneyitiesDao.add(cashReceivable);
                    //判断类型是否为：分红
                }else if (fundDatum.getReType().equals("分红")){//现金应收应付产生分红的反冲销数据
                    //修改现金应收应付对象的交易类型为：分红
                    cashReceivable.setBusinType("分红");
                    //修改现金应收应付的资金方向为流出
                    cashReceivable.setCapFlow(-1);
                    //通过现金应收应付调用添加方法将现金应收应付对象添加进去
                    moneyitiesDao.add(cashReceivable);
                    //判断类型是否为:买入证券，并且调拨方法为流出：证券买入卖出时需要添加到证券应收应付
                }else if (fundDatum.getReType().equals("买入证券") && fundDatum.getDial()==-1){//证券买卖结算证券应收应付的反冲销：买入
                    //修改证券应收应付对象的调拨类型为：买入
                    payable.setBusinType("买入");
                    //修改证券应收应付对象的资金流向为流入
                    payable.setCapflow(1);
                    //通过证券应收应付dao对象将证券应收应付对象添加进去
                    securitiesDao.add(payable);
                    //判断是否为：卖出证券，并且调拨方向为流入
                }else if (fundDatum.getReType().equals("卖出证券") && fundDatum.getDial()==1){//证券买卖结算证券应收应付的反冲销:卖出
                    //修改证券应收应付对象的调拨类型为：卖出
                    payable.setBusinType("卖出");
                    //修改证券应收应付对象的资金流向为流出
                    payable.setCapflow(-1);
                    //通过证券应收应付dao对象将证券应收应付对象添加进去
                    securitiesDao.add(payable);
                }
            }

            //判断资金调拨数据集合的大小不为0
            if (fundData.size()!=0){
                //定义变量记录流入金额和流出金额
                double intoFlow=0.0,outFlow=0.0;
                //定义一个保存基金编号和现金编号的变量
                String fundId=null;
                Integer caId=null;
                //遍历(未处理)数据，将数据添加到现金库存
                for (FundAllocation fundDatum : fundData) {
                    //从遍历对象中获取基金编号用变量接收
                    fundId=fundDatum.getFundId();
                    //从遍历对象中获取现金编号用变量接收
                    caId=fundDatum.getCaId();
                    //判断资金调拨方向为流入
                    if (fundDatum.getDial()==1){
                        //流入则将流入变量递增加调拨金额
                        intoFlow+=fundDatum.getReMoney();
                    }else if (fundDatum.getDial()==-1){//数据为流出
                        //流出则将流出变量递增加调拨金额
                        outFlow+=fundDatum.getReMoney();
                    }

                    //创建划款对象
                    TransferInstruction instruction = new TransferInstruction();
                    //修改对象的金额为遍历对象中的调拨金额
                    instruction.setMoney(fundDatum.getReMoney());
                    //修改划款日期为遍历对象中的业务日期
                    instruction.setTranDate(dateFormat.format(fundDatum.getBusinDate()));
                    //修改到账日期为遍历对象中的调拨日期
                    instruction.setArrival(dateFormat.format(fundDatum.getReDate()));
                    //修改划款用途为遍历对象中的调拨类型
                    instruction.setPurpose(fundDatum.getReType());
                    //修改划款现金编号为遍历对象中的现金编号
                    instruction.setCaId(fundDatum.getCaId());
                    //修改流入账户编号的值为0
                    instruction.setCaIds(0);
                    //调用划款指令添加方法
                    transferInstructionDao.add(instruction);
                }
                //将流入流出添加到现金库存当中 ：在这之前需要判断现金库存当中是否已经存在一行数据，如果存在则修改金额，如果不存在需要插入一行数据
                //通过库存统计dao对线调用查询现金库存数量 :判断如果大于0则修改数据
                if (repertoryTotalDao.cashStockRowNum()>0){
                    //通过库存统计dao对象调用修改现金库存流入方法，传入流入金额和当天日期
                    repertoryTotalDao.updateCashStockInto(intoFlow,dateFormat.format(new Date()));
                    //通过库存统计dao对象调用修改现金库存流出方法，传入流出金额和当天日期
                    repertoryTotalDao.updateCashStockOut(outFlow,dateFormat.format(new Date()));
                }else{
                    //通过库存统计dao对象调用如果为空添加现金库存方法：传入基金编号，现金编号，流入金额，当天日期
                    repertoryTotalDao.ifNulladdCashStock(fundId,caId,intoFlow,dateFormat.format(new Date()));
                    //通过库存统计dao对象调用修改现金库存的流入方法：传入流出金额，当天日期
                    repertoryTotalDao.updateCashStockOut(outFlow,dateFormat.format(new Date()));
                }
                //通过库存统计dao对象调用修改基金数据方法，传入当天日期
                repertoryTotalDao.updateFundData(dateFormat.format(new Date()));
            }
            //返回true
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 显示库存页面数据
     * @param request
     * @return 返回页面显示数据
     */
    public List<RepertoryTotal> getList(HttpServletRequest request){
        //创建日期转换格式对象
        SimpleDateFormat dateFormat = new SimpleDateFormat();
        //获取当天日期，定义变量接收
        String toDay = dateFormat.format(new Date());
        //获取session对象
        HttpSession session = request.getSession();
        //在session当中得出sn值并且转换成用户对象
        users users = (users) session.getAttribute("sn");
        //获取用户编号定义变量接收
        Integer userId = users.getUserId();
        //从请求中得出date操作日期定义字符串变量接收：获得统计日期，用户得出查询指定日期的库存
        String dates=request.getParameter("date");
        //判断日期不等于空，并且清除两端空格后也不等于空字符串
        if (dates!=null && dates.trim().equals("")){
            //让日期变量为空
            dates=null;
        }
        //定义一个库存统计对象集合
        ArrayList<RepertoryTotal> list = new ArrayList<>();
        //为集合添加数据，传入不同的库存统计对象，对象的值分别为：现金库存，库存统计dao对象调用的基金编号，
        // 调用的查询用户名方法传入用户id，当天日期，调用的现金库存数量传入操作日期
        list.add(new RepertoryTotal("现金库存", repertoryTotalDao.queryFundId(),
                repertoryTotalDao.queryUserName(userId), toDay, repertoryTotalDao.cashStockCount(dates)));
        //证券库存
        list.add(new RepertoryTotal("证券库存", repertoryTotalDao.queryFundId(),
                repertoryTotalDao.queryUserName(userId), toDay, repertoryTotalDao.securitiesStockCount(dates)));
        //证券应收应付库存
        list.add(new RepertoryTotal("证券应收应付库存", repertoryTotalDao.queryFundId(),
                repertoryTotalDao.queryUserName(userId), toDay, repertoryTotalDao.secRecAndPayStockCount(dates)));
        //现金应收应付库存
        list.add(new RepertoryTotal("现金应收应付库存", repertoryTotalDao.queryFundId(),
                repertoryTotalDao.queryUserName(userId), toDay, repertoryTotalDao.cashRecAndPayStockCount(dates)));
        //ta库存
        list.add(new RepertoryTotal("ta库存", repertoryTotalDao.queryFundId(),
                repertoryTotalDao.queryUserName(userId), toDay, repertoryTotalDao.taStockCount(dates)));
        //返回集合
        return list;
    }
}
